package cn.sumpu.app.guoguojie.biz.impl;

import java.util.Date;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import cn.sumpu.app.guoguojie.biz.AccountBiz;
import cn.sumpu.app.guoguojie.biz.IdentifierBiz;
import cn.sumpu.app.guoguojie.constant.TransactionType;
import cn.sumpu.app.guoguojie.dao.AccountDao;
import cn.sumpu.app.guoguojie.dao.AccountLogDao;
import cn.sumpu.app.guoguojie.domain.Account;
import cn.sumpu.app.guoguojie.domain.AccountLog;
import cn.sumpu.app.guoguojie.exception.AppBusinessException;
import cn.sumpu.app.guoguojie.util.Common;
import cn.sumpu.app.guoguojie.util.PageModel;

public class AccountBizImpl implements AccountBiz {
    private static Logger                logger = LoggerFactory.getLogger(AccountBizImpl.class);

    private AccountDao                   accountDao;
    private AccountLogDao                accountLogDao;
    private DataSourceTransactionManager transactionManager;
    @Autowired
    private IdentifierBiz                identifierBiz;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public void setAccountLogDao(AccountLogDao accountLogDao) {
        this.accountLogDao = accountLogDao;
    }

    public void setTransactionManager(DataSourceTransactionManager transactionManager) {
        this.transactionManager = transactionManager;
    }

    @Override
    public Account getAccountByAccountId(String accountId) throws AppBusinessException {
        if (null == accountId) {
            throw new AppBusinessException("Account id is null");
        }
        return accountDao.getAccountById(accountId);
    }

    @Override
    public PageModel getAccountLog(Map<String, Object> params) throws AppBusinessException {
        int count = accountLogDao.countAccountLogList(params);
        Object pageObj = params.get("page");
        int page = Integer.parseInt(String.valueOf(pageObj));
        if (null == pageObj) {
            params.put("page", 1);
        } else {
            params.put("page", page);
        }
        Object pageSizeObj = params.get("pageSize");
        int pageSize = Integer.parseInt(String.valueOf(pageSizeObj));
        if (null == pageSizeObj) {
            params.put("pageSize", "20");
        } else {
            params.put("pageSize", pageSize);
        }
        params.put("startId", (page - 1) * pageSize);
        List<AccountLog> aclList = accountLogDao.getAccountLogList(params);
        PageModel pm = new PageModel();
        pm.setCurrentPage(page);
        pm.setList(aclList);
        pm.setPageSize(pageSize);
        pm.setTotalRecord(count);
        pm.setTotalPage((count + pageSize - 1) / pageSize);
        return pm;
    }

    @Override
    public Account getAccountByMemberId(String memberId) throws AppBusinessException {
        return accountDao.getAccountByMember(memberId);
    }

    @Override
    public void createAccountByMemberId(String memberId) throws AppBusinessException {
        Account ac = new Account();
        ac.setIdentifier(identifierBiz.generateId("account"));
        ac.setMember(memberId);
        ac.setEnabled(true);
        accountDao.insertAccount(ac);
    }

    @Override
    public void log(AccountLog log) throws AppBusinessException {
        accountLogDao.insertAccountLog(log);
    }

    @Override
    public void transferRmbByMemberId(String fromMemberId, String toMemberId, double rmb, String summary, String operator, TransactionType transactionType)
                                                                                                                                                           throws AppBusinessException {
        Account fromAccount = getAccountByMemberId(fromMemberId);
        Account toAccount = getAccountByMemberId(toMemberId);
        transferRmbByAccountId(fromAccount.getIdentifier(), toAccount.getIdentifier(), rmb, summary, operator, transactionType);
    }

    @Override
    public void transferRmbByAccountId(String fromAccountId, String toAccountId, double rmb, String summary, String operator, TransactionType transactionType)
                                                                                                                                                               throws AppBusinessException {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();// 事务定义类
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);// 设置事务传播属性
        def.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);// 设置事务隔离级别
        def.setTimeout(10);// 设置事务超时时间
        TransactionStatus status = transactionManager.getTransaction(def);// 返回事务对象
        try {
            Account fromAccount = getAccountByAccountId(fromAccountId);
            Account toAccount = getAccountByAccountId(toAccountId);
            if (verifyAccount(fromAccount) && verifyAccount(toAccount) && checkAccountForRmb(fromAccount, rmb)) {
                fromAccount.setRmb(fromAccount.getRmb() - rmb);
                toAccount.setRmb(toAccount.getRmb() + rmb);
                accountDao.updateAccount(fromAccount);
                accountDao.updateAccount(toAccount);
                // 产生一条人民币支出交易日志
                AccountLog log = new AccountLog();
                log.setIdentifier(identifierBiz.generateId("account_log"));
                log.setAccount(fromAccount.getIdentifier());
                log.setAccountName(fromAccount.getName());
                log.setWithdrawRmb(rmb);
                log.setWithdrawRmbAccount(toAccount.getIdentifier());
                log.setOperator(operator);
                log.setTransactionType(transactionType.getValue());
                log.setTransactionTime(new Date());
                log.setRmb(fromAccount.getRmb());
                log.setGgb(fromAccount.getGgb());
                log.setSummary(summary);
                log(log);
                // 产生一条人民币收入交易日志
                AccountLog log0 = new AccountLog();
                log0.setIdentifier(identifierBiz.generateId("account_log"));
                log0.setAccount(toAccount.getIdentifier());
                log0.setAccountName(toAccount.getName());
                log0.setDepositRmb(rmb);
                log0.setDepositRmbAccount(fromAccount.getIdentifier());
                log0.setOperator(operator);
                log0.setTransactionType(transactionType.getValue());
                log0.setTransactionTime(new Date());
                log0.setRmb(toAccount.getRmb());
                log0.setGgb(toAccount.getGgb());
                log0.setSummary(summary);
                log(log0);
                transactionManager.commit(status);// 提交事务
            }
        } catch (Exception e) {
            if (logger.isErrorEnabled()) {
                logger.error("Transfer rmb fail", e);
            }
            transactionManager.rollback(status);// 回滚事务
            throw new AppBusinessException(e);
        }
    }

    @Override
    public void depositRmbByAccountId(String accountId, double rmb, String summary, String operator, TransactionType transactionType)
                                                                                                                                     throws AppBusinessException {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();// 事务定义类
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);// 设置事务传播属性
        TransactionStatus status = transactionManager.getTransaction(def);// 返回事务对象
        def.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);// 设置事务隔离级别
        def.setTimeout(10);// 设置事务超时时间
        try {
            Account toAccount = getAccountByAccountId(accountId);
            if (verifyAccount(toAccount)) {
                toAccount.setRmb(toAccount.getRmb() + rmb);
                accountDao.updateAccount(toAccount);
                // 产生一条人民币收入交易日志
                AccountLog log0 = new AccountLog();
                log0.setIdentifier(identifierBiz.generateId("account_log"));
                log0.setAccount(toAccount.getIdentifier());
                log0.setAccountName(toAccount.getName());
                log0.setDepositRmb(rmb);
                log0.setOperator(operator);
                log0.setTransactionType(transactionType.getValue());
                log0.setTransactionTime(new Date());
                log0.setRmb(toAccount.getRmb());
                log0.setGgb(toAccount.getGgb());
                log0.setSummary(summary);
                log(log0);
                transactionManager.commit(status);
            }
        } catch (Exception e) {
            if (logger.isErrorEnabled()) {
                logger.error("Deposit rmb fail", e);
            }
            transactionManager.rollback(status);// 回滚事务
            throw new AppBusinessException(e);
        }
    }

    @Override
    public void withdrawRmbByAccountId(String accountId, double rmb, String summary, String operator, TransactionType transactionType)
                                                                                                                                      throws AppBusinessException {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();// 事务定义类
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);// 设置事务传播属性
        TransactionStatus status = transactionManager.getTransaction(def);// 返回事务对象
        def.setIsolationLevel(TransactionDefinition.ISOLATION_SERIALIZABLE);// 设置事务隔离级别
        def.setTimeout(10);// 设置事务超时时间
        try {
            Account toAccount = getAccountByAccountId(accountId);
            if (checkAccountForRmb(toAccount, rmb) && verifyAccount(toAccount)) {
                toAccount.setRmb(toAccount.getRmb() - rmb);
                accountDao.updateAccount(toAccount);
                // 产生一条人民币支出交易日志
                AccountLog log0 = new AccountLog();
                log0.setIdentifier(identifierBiz.generateId("account_log"));
                log0.setAccount(toAccount.getIdentifier());
                log0.setAccountName(toAccount.getName());
                log0.setWithdrawRmb(rmb);
                log0.setOperator(operator);
                log0.setTransactionType(transactionType.getValue());
                log0.setTransactionTime(new Date());
                log0.setRmb(toAccount.getRmb());
                log0.setGgb(toAccount.getGgb());
                log0.setSummary(summary);
                log(log0);
                transactionManager.commit(status);
            }
        } catch (Exception e) {
            if (logger.isErrorEnabled()) {
                logger.error("Withdraw rmb fail", e);
            }
            transactionManager.rollback(status);// 回滚事务
            throw new AppBusinessException(e);
        }
    }

    @Override
    public void depositRmbByMemberId(String memberId, double rmb, String summary, String operator, TransactionType transactionType) throws AppBusinessException {
        Account account = accountDao.getAccountByMember(memberId);
        depositRmbByAccountId(account.getIdentifier(), rmb, summary, operator, transactionType);

    }

    @Override
    public void withdrawRmbByMemberId(String memberId, double rmb, String summary, String operator, TransactionType transactionType)
                                                                                                                                    throws AppBusinessException {
        Account account = accountDao.getAccountByMember(memberId);
        withdrawRmbByAccountId(account.getIdentifier(), rmb, summary, operator, transactionType);

    }

    @Override
    public Boolean verifyAccountByAccountId(String accountId) throws AppBusinessException {
        Account account = getAccountByAccountId(accountId);
        if (!Common.empty(account) && !Common.empty(account.getEnabled()) && account.getEnabled()) {
            return true;
        } else {
            if (logger.isErrorEnabled()) {
                logger.error("Account [identifier=" + accountId + "] is abnormal!");
            }
            return false;
        }
    }

    @Override
    public Boolean verifyAccountByMemberId(String memberId) throws AppBusinessException {
        Account account = getAccountByMemberId(memberId);
        if (!Common.empty(account) && !Common.empty(account.getEnabled()) && account.getEnabled()) {
            return true;
        } else {
            if (logger.isErrorEnabled()) {
                logger.error("Account [member=" + memberId + "] is abnormal!");
            }
            return false;
        }
    }

    public Boolean verifyAccount(Account account) throws AppBusinessException {
        if (!Common.empty(account) && !Common.empty(account.getEnabled()) && account.getEnabled()) {
            return true;
        } else {
            if (logger.isErrorEnabled()) {
                logger.error(account.toString() + " is abnormal!");
            }
            return false;
        }
    }

    public Boolean checkAccountForRmb(Account account, double rmbAmount) throws AppBusinessException {
        if (rmbAmount > 0 && account.getRmb() - rmbAmount >= 0) {
            return true;
        } else {
            if (logger.isErrorEnabled()) {
                logger.error(account.toString() + " not enough rmb!");
            }
            return false;
        }
    }

}
